/*
 * @(#)XfdmConfig.java        1.0 2000/05/09
 *
 * This file is part of Xfuzzy 3.0, a design environment for fuzzy logic
 * based systems.
 *
 * (c) 2000 IMSE-CNM. The authors may be contacted by the email address:
 *                    xfuzzy-team@imse.cnm.es
 *
 * Xfuzzy is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 *
 * Xfuzzy is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 */

package xfuzzy.xfdm.model;

import java.io.*;
import xfuzzy.xfds.*;
import xfuzzy.lang.Specification;


/**
 * Configuraci�n del proceso de extracci�n de conocimiento
 * 
 * @author Francisco Jos� Moreno Velo
 *
 */
public class XfdmConfig {

	//----------------------------------------------------------------------------//
	//                            MIEMBROS PRIVADOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Fichero en el que se encuentra el conjunto de datos a utilizar
	 */
	private File datasetfile;
	
	/**
	 * Fichero en el que se encuentra el conjunto de datos de test
	 */
	private File datatestfile;
	
	/**
	 * Fichero en el que se almacenr� la evaluaci�n del resultado
	 */
	private File logfile;
	
	/**
	 * Conjunto de datos a utilizar
	 */
	private XfdsDataSet dataset;
	
	/**
	 * Conjunto de datos de test
	 */
	private XfdsDataSet datatest;
	
	/**
	 * Estilo com�n a todas las variables de entrada
	 */
	private XfdmInputStyle commonstyle;
	
	/**
	 * Estilo particular de cada variable de entrada
	 */
	private XfdmInputStyle[] inputstyle;
	
	/**
	 * Estilo del sistema a construir
	 */
	private XfdmSystemStyle systemstyle;
	
	/**
	 * Configuraci�n del algoritmo a utilizar
	 */
	private XfdmAlgorithm algorithm;

	/**
	 * Sistema difuso
	 */
	private Specification spec;
	
	//----------------------------------------------------------------------------//
	//                               CONSTRUCTOR                                  //
	//----------------------------------------------------------------------------//

	/**
	 * Constructor
	 */
	public XfdmConfig() {
		datasetfile = null;
		dataset = null;
		datatestfile = null;
		datatest = null;
		logfile = null;
		commonstyle = null;
		inputstyle = null;
		systemstyle = null;
		algorithm = null;
		spec = null;
	}

	//----------------------------------------------------------------------------//
	//                             M�TODOS P�BLICOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Representacion en el fichero de configuracion
	 */
	public String toXML() {
		String eol = System.getProperty("line.separator", "\n");
		String sysname = this.spec.getName();
		String code = "<xfuzzy>"+eol;
		code += "\t<xfdm system=\""+sysname+"\">"+eol;

		if(datasetfile != null) {
			code += "\t\t<dataset file=\""+datasetfile.getAbsolutePath()+"\"></dataset>"+eol;
		}

		if(datasetfile != null) {
			code += "\t\t<datatest file=\""+datatestfile.getAbsolutePath()+"\"></datatest>"+eol;
		}
		
		if(logfile != null) {
			code += "\t\t<log file=\""+logfile.getAbsolutePath()+"\"></log>"+eol;
		}		

		if(commonstyle != null) {
			code += commonstyle.toXML()+eol;
		}
		if(inputstyle != null) for(int i=0; i<inputstyle.length; i++) {
			if(inputstyle[i] != null) code += inputstyle[i].toXML()+eol;
		}
		if(systemstyle != null) {
			code += systemstyle.toXML()+eol;
		}
		if(algorithm != null) {
			code += algorithm.toXML()+eol;
		}
		code += "\t</xfdm>"+eol;
		code += "</xfuzzy>"+eol;
		return code;
	}

	/**
	 * Almacenar la configuraci�n en un fichero
	 */
	public boolean save(File file, boolean append) {
		String code = toXML();
		byte buf[] = code.getBytes();

		try {
			OutputStream stream = new FileOutputStream(file,append);
			stream.write(buf);
			stream.close();
		}
		catch (IOException e) { return false; }
		return true;
	}

	/**
	 * Obtiene el estado de la configuraci�n (pasos dados en el proceso de
	 * configuraci�n)
	 * @return
	 */
	public int getStep() {
		if(dataset == null) return 0;
		if(algorithm == null) return 1;
		if(!testInputStyle()) return 2;
		if(!testSystemStyle()) return 3;
		return 4;
	}
	
	/**
	 * Verifica que el estilo de variables de entrada es correcto
	 */
	public boolean testInputStyle() {
		if(dataset == null) return false;
		if(commonstyle != null) return true;
		if(inputstyle == null) return false;
		if(inputstyle.length != dataset.getNumberOfInputs()) return false;
		return true;
	}

	/**
	 * Verifica que el estilo del sistema es correcto
	 */
	public boolean testSystemStyle() {
		if(dataset == null) return false;
		if(dataset.getNumberOfOutputs()<=0) return false;
		return (systemstyle != null);
	}

	/**
	 * Verifica que la configuracion puede ejecutarse
	 */
	public boolean isReadyToRun() {
		return (dataset != null && testInputStyle() && 
				testSystemStyle() && algorithm != null);
	}

	/**
	 * Obtiene un objeto con la lista de patrones
	 */
	public boolean loadDataSet() {
		try {
			FileInputStream fis = new FileInputStream(datasetfile);
			XfdsParser parser = new XfdsParser(fis);
			XfdsDataSet ds = parser.parse();
			if(ds == null) return false;
			this.dataset = ds;
			return true;
		}
		catch(Exception ex) {
			return false;
		}
	}

	/**
	 * Obtiene un objeto con el conjunto de test
	 */
	public boolean loadDataTest() {
		try {
			FileInputStream fis = new FileInputStream(datatestfile);
			XfdsParser parser = new XfdsParser(fis);
			XfdsDataSet ds = parser.parse();
			if(ds == null) return false;
			this.datatest = ds;
			return true;
		}
		catch(Exception ex) {
			return false;
		}
	}
	
	/**
	 * Obtiene un objeto con la lista de patrones
	 */
	public boolean setDataSet(File file) {
		try {
			this.datasetfile = file;
			FileInputStream fis = new FileInputStream(datasetfile);
			XfdsParser parser = new XfdsParser(fis);
			XfdsDataSet ds = parser.parse();
			if(ds == null) return false;
			this.dataset = ds;
			return true;
		}
		catch(Exception ex) {
			return false;
		}
	}

	/**
	 * Obtiene un objeto con el conjunto de test
	 */
	public boolean setDataTest(File file) {
		try {
			this.datatestfile = file;
			FileInputStream fis = new FileInputStream(datatestfile);
			XfdsParser parser = new XfdsParser(fis);
			XfdsDataSet ds = parser.parse();
			if(ds == null) return false;
			this.datatest = ds;
			return true;
		}
		catch(Exception ex) {
			return false;
		}
	}
	
	/**
	 * Obtiene el fichero del conjunto de datos
	 * @return
	 */
	public File getDataSetFile() {
		return this.datasetfile;
	}
	
	/**
	 * Obtiene el fichero del conjunto de test
	 * @return
	 */
	public File getDataTestFile() {
		return this.datatestfile;
	}
	
	/**
	 * Obtiene el conjunto de datos utilizado en el proceso
	 * @return
	 */
	public XfdsDataSet getDataSet() {
		return this.dataset;
	}

	/**
	 * Obtiene el conjunto de test utilizado en el proceso
	 * @return
	 */
	public XfdsDataSet getDataTest() {
		return this.datatest;
	}	
	
	/**
	 * Asigna el fichero de almacenamiento de la evaluaci�n
	 * @param file
	 */
	public void setLogFile(File file) {
		this.logfile = file;
	}
	
	/**
	 * Obtiene el fichero de almacenamiento de la evaluaci�n
	 * @return
	 */
	public File getLogFile() {
		return this.logfile;
	}
	
	/**
	 * Obtiene el tipo de sistema a construir
	 * @return
	 */
	public XfdmSystemStyle getSystemStyle() {
		return this.systemstyle;
	}

	/**
	 * Asigna el tipo de sistema a construir
	 * @param style
	 */
	public void setSystemStyle(XfdmSystemStyle style) {
		this.systemstyle = style;
	}
	
	/**
	 * Obtiene el estilo com�n para todas las variables de entrada
	 * @return
	 */
	public XfdmInputStyle getCommonInputStyle() {
		return this.commonstyle;
	}
	
	/**
	 * Asigna el estilo com�n para todas las variables de entrada
	 */
	public void setCommonInputStyle(XfdmInputStyle style) {
		this.commonstyle = style;
	}
	
	/**
	 * Obtiene la lista de estilos particulares de cada variable de entrada
	 * @return
	 */
	public XfdmInputStyle[] getInputStyles() {
		return this.inputstyle;
	}

	/**
	 * Asigna la lista de estilos particulares de cada variable de entrada
	 * @param styles
	 */
	public void setInputStyles(XfdmInputStyle[] styles) {
		this.inputstyle = styles;
	}
	
	/**
	 * A�ade un estilo de variable de entrada
	 * @param style
	 */
	public void addInputStyle(XfdmInputStyle style) {
		if(style.getIndex() <0) this.commonstyle = style;
		else if(inputstyle == null) {
			inputstyle = new XfdmInputStyle[1];
			inputstyle[0] = style;
		}
		else {
			XfdmInputStyle[] aux = new XfdmInputStyle[inputstyle.length+1];
			System.arraycopy(inputstyle, 0, aux, 0, inputstyle.length);
			aux[inputstyle.length] = style;
			inputstyle = aux;
		}
	}
	
	/**
	 * Obtiene la referencia al algoritmo de extracci�n de conocimiento
	 * @return
	 */
	public XfdmAlgorithm getAlgorithm() {
		return this.algorithm;
	}
	
	/**
	 * Asigna la selecci�n del algoritmo de extracci�n de conocimiento
	 * @param alg
	 */
	public void setAlgorithm(XfdmAlgorithm alg) {
		this.algorithm = alg;
	}
	
	/**
	 * Obtiene el sistema difuso sobre el que aplicar la herramienta
	 * @return
	 */
	public Specification getSpecification() {
		return this.spec;
	}
	
	/**
	 * Asigna el sistema difuso sobre el que aplicar la herramienta
	 * @param spec
	 */
	public void setSpecification(Specification spec) {
		this.spec = spec;
	}
}
